SpringBoot小例子进阶
本部分代码是基于SpringBoot基础应用
博文的。
代码结构如下:
demo // 项目名
|- .idea
|- .mvn
|- src // 代码存放区
|- main
|- java
|- com.example.demo // java包
|- aspect // 拦截器
|- HttpAspect.java
|- controller // 控制器
|- PersonController
|- domain // 实体类
|- Person
|- Result // 定义异常的响应信息的格式
|- enums
|- ResultEnum // 定义异常的code和信息
|- exception // 自定义异常
|- PersonException
|- handle // 捕获异常
|- ExceptionHandle
|- repository // jpa操作
|- PersonRepository
|- service // 处理业务逻辑
|- PersonService
|- DemoApplication.java // 项目启动类
|- resources
|- static // 用于存放css,js等样式文件
|- templates // 用于存放html文件
application.properties // 项目配置文件
|- test //测试代码存放区
|- target
.gitignore
mvnw
mvnw.cmd
demo.iml
pom.xml // 项目对象模型,添加项目依赖等配置
实现表单验证
要求: age小于18的数据无法入库
修改Person类
package com.example.demo.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.Min;
@Entity
public class Person {
@Id
@GeneratedValue
private Integer id;
private String name;
// @Min 使得该属性必须大于18,当数值小于18时,有提示信息
@Min(value = 18, message = "年龄小于18无法添加")
private Integer age;
public Person() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
修改PersonController类addPerson()
/**
* 通过post方式访问localhost:8080/person?name=Jane&age=10可添加数据
* @param person 要添加的person对象
* @param bindingResult 获取绑定结果信息
* @return 返回Person类信息
*/
@PostMapping(value = "/person")
public Person addPerson(@Valid Person person, BindingResult bindingResult) {
// 当输入数据不符合要求时,后台输出错误信息
if (bindingResult.hasErrors()) {
System.out.println(bindingResult.getFieldError().getDefaultMessage());
return null;
}
return personRepository.save(person);
}
@Valid
用于对传入的数据进行校验。
使用AOP处理请求
什么是AOP
(1)AOP(面向切面, Aspect Oriented Programming)是一种编程范式,是一种程序设计思想。思想是将通用逻辑从业务逻辑中分离出来
将纵向的分析变为横向分析,从而将通用逻辑从业务逻辑中分离出来。
(2)除了AOP还有OOP(面向对象,Object Oriented Programming),POP(面向过程,Proceduer Oriented Programming)
AOP统一处理请求日志
要求:记录每一个http请求
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
创建HttpAspect类
@Aspect
实现切面注入;@Component
将该类注册到SpringBoot容器中
package com.example.demo.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
// 切面注入
@Aspect
@Component
public class HttpAspect {
// 日志对象
private final static Logger LOGGER = LoggerFactory.getLogger(HttpAspect
.class);
// 指明哪些方法需要执行AOP
@Pointcut("execution(public * com.example.demo.controller.PersonController" +
".*(..))")
public void log() {}
/**
* 该方法功能是将请求中的信息输出至日志中
* @Before 在使用PersonController中方法前先执行该注解下的方法
* @param joinpoint 目标类连接点对象
*/
@Before("log()")
public void doBefore(JoinPoint joinpoint) {
ServletRequestAttributes attributes = (ServletRequestAttributes)
RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 获取url
LOGGER.info("url = {}", request.getRequestURL());
// 获取请求方式
LOGGER.info("method = {}", request.getMethod());
// 获取请求方的ip
LOGGER.info("ip = {}", request.getRemoteAddr());
// 获取被调用的方法名
LOGGER.info("class_method = {}",
joinpoint.getSignature().getDeclaringTypeName() +
"." + joinpoint.getSignature().getName() + "()");
// 获取请求参数
LOGGER.info("args = {}", joinpoint.getArgs());
}
/** 该方法功能是将响应中的信息输出至日志中
* @AfterReturning 使得该类可以接收HttpResponse中对象信息
* @param object 返回的对象信息
*/
@AfterReturning(returning = "object", pointcut = "log()")
public void doAfterReturning(Object object) {
LOGGER.info("response = {}", object.toString());
}
}
统一异常处理
要求:获取Person对象的age并判断
age < 12 : 返回"正在上小学"
age > 12 && age < 15: 返回"正在上初中"
定义异常响应信息格式
package com.example.demo.domain;
public class Result<T> {
private Integer code; // 错误码
private String msg; // 提示信息
private T data; // 具体内容
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
自定义异常类
package com.example.demo.exception;
import com.example.demo.enums.ResultEnum;
public class PersonException extends RuntimeException {
private Integer code;
public PersonException(ResultEnum resultEnum) {
super(resultEnum.getMsg());
this.code = resultEnum.getCode();
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
规范响应code和msg
package com.example.demo.enums;
public enum ResultEnum {
UNKNOW_ERROR(-1, "未知错误"),
SUCCESS(200, "添加成功"),
PRIMARY_SCHOOL(403, "在上小学"),
MIDDLE_SCHOOL(404, "在上初中"),
;
private Integer code;
private String msg;
ResultEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
进行异常捕获
package com.example.demo.handle;
import com.example.demo.domain.Result;
import com.example.demo.exception.PersonException;
import com.example.demo.util.ResultUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
public class ExceptionHandle {
private final static Logger LOGGER = LoggerFactory.getLogger
(ExceptionHandle.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result handle(Exception e){
if (e instanceof PersonException) {
PersonException personException = (PersonException) e;
return ResultUtil.error(personException.getCode(),
personException.getMessage());
} else {
LOGGER.error("[系统异常] {}", e);
return ResultUtil.error(-1, "未知错误");
}
}
}
进行逻辑判断,从而判断异常
package com.example.demo.service;
import com.example.demo.domain.Person;
import com.example.demo.enums.ResultEnum;
import com.example.demo.exception.PersonException;
import com.example.demo.repository.PersonRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class PersonService {
@Autowired
private PersonRepository personRepository;
public void getAge(Integer id) throws Exception{
Person person = personRepository.findOne(id);
Integer age = person.getAge();
if (age < 10) {
throw new PersonException(ResultEnum.PRIMARY_SCHOOL);
} else if (age > 10 && age < 16) {
throw new PersonException(ResultEnum.MIDDLE_SCHOOL);
}
}
}
单元测试
对Service进行测试
package com.example.demo;
import com.example.demo.domain.Person;
import com.example.demo.service.PersonService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private PersonService personService;
@Test
public void findOneTest() {
Person person = personService.findOne(9);
// 断言
Assert.assertEquals(new Integer(19), person.getAge());
}
}
对API进行测试
package com.example.demo.controller;
import com.example.demo.domain.Person;
import com.example.demo.repository.PersonRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet
.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class PersonControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void personList() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/person")).
// 对状态码进行断言
andExpect(MockMvcResultMatchers.status().isOk()).
// 对响应文本进行断言
andExpect(MockMvcResultMatchers.content().string(""));
}
}
This blog is under a CC BY-NC-SA 3.0 Unported License
本文链接:http://yov.oschina.io/article/框架/Spring Boot/SpringBoot小例子进阶/